package com.jasiri.project.lib.location

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.location.Geocoder
import android.location.Location
import android.location.LocationManager
import android.os.Looper
import androidx.core.content.ContextCompat
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import com.jasiri.project.utils.log.HHLog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import org.json.JSONObject
import java.util.Locale

/**
 * 读取模糊位置
 * <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 *
 * implementation 'com.google.android.gms:play-services-location:21.0.1'
 *
 * 上报模式与device info一样，没有额外的zip字段
 * path: /v1/userLocation
 */
object JasiriLocationHelper {

    private var fusedLocationClient: FusedLocationProviderClient? = null

    // 定位频率参数配置
    private val locationRequest =
        LocationRequest.Builder(Priority.PRIORITY_BALANCED_POWER_ACCURACY, 2000L)
            .setMinUpdateIntervalMillis(1500L)
            .build()

    private var locationCallback: LocationCallback? = null
    private var currentJob: Job? = null
    private var timeoutJob: Job? = null
    private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)

    // 并发保护
    @Volatile
    private var isLocating = false
    private val lock = Any()

    /**
     * 初始化
     */
    fun init(context: Context) {
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(context.applicationContext)
    }

    /**
     * 开始定位，需保证调用前权限已授权
     * @param onResult 定位成功或失败的回调，可能返回null
     */
    fun readLocation(context: Context, onResult: (JSONObject?) -> Unit) {
        synchronized(lock) {
            if (isLocating) {
                onResult(null) // 正在定位中，拒绝新请求
                return
            }
            isLocating = true
        }

        if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            onResult(null) // 无权限
            return
        }

        // 必须确认已调用
        if (fusedLocationClient == null) {
            fusedLocationClient = LocationServices.getFusedLocationProviderClient(context.applicationContext)
        }

        // 启动超时计时器（例如：30秒）
        timeoutJob = coroutineScope.launch {
            delay(30000L)
            // 使用 getLastKnownLocation
            tryGetLastKnownLocation(context, onResult)
        }

        // 定位回调
        locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult) {
                val location = locationResult.lastLocation
                if (location == null) {
                    // 使用 getLastKnownLocation
                    tryGetLastKnownLocation(context, onResult)
                    return
                }

                HHLog.e(">>>>>>location success>>>result, latitude: " + location.latitude + ",longitude: "+ location.longitude)
                currentJob = coroutineScope.launch {
                    val info = safeGetLocationInfo(context, location)
                    complete(info, onResult)
                }
            }
        }

        //
        try {
            fusedLocationClient?.let { client ->
                locationCallback?.let { callback ->
                    client.requestLocationUpdates(locationRequest, callback, Looper.getMainLooper())
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            complete(null, onResult)
        }
    }

    /**
     * 停止定位，释放资源
     */
    private fun stopLocation() {
        locationCallback?.let {
            fusedLocationClient?.removeLocationUpdates(it)
        }
        locationCallback = null

        currentJob?.cancel()
        currentJob = null
    }

    /**
     * 取消定位并回调
     */
    fun cancel() {
        complete(null) {} // 安全取消
    }

    /**
     * 停止定位并回调
     */
    private fun complete(info: JSONObject?, onResult: (JSONObject?) -> Unit) {
        synchronized(lock) {
            if (!isLocating) return
            isLocating = false
        }

        stopLocation() // 再次尝试清理资源
        timeoutJob?.cancel()
        timeoutJob = null
        currentJob?.cancel()
        currentJob = null

        coroutineScope.launch(Dispatchers.Main) {
            onResult(info)
        }
    }

    /**
     * Geocoder可能阻塞甚至ANR，对它做超时保护
     */
    private suspend fun safeGetLocationInfo(context: Context, location: Location): JSONObject? =
        withContext(Dispatchers.IO) {
            try {
                withTimeout(30000L) { // 最长等待 30 秒
                    getLocationInfoFromLocation(context, location)
                }
            } catch (e: Exception) {
                e.printStackTrace()
                null
            }
        }

    /**
     * Geocoder 解析
     */
    private fun getLocationInfoFromLocation(context: Context, location: Location): JSONObject? {
        val geocoder = Geocoder(context, Locale.getDefault())
        return try {
            val addresses = geocoder.getFromLocation(location.latitude, location.longitude, 1)
            if (addresses.isNullOrEmpty()) return null
            val address = addresses[0]
            JSONObject().apply {
                put("longitude", location.longitude.toString())
                put("latitude", location.latitude.toString())
                put("province", address.adminArea ?: "")
                put("city", address.locality ?: "")
                put("county", address.subLocality ?: "")
                put("street", "")// 建议模糊模式下不要取这个值
                put("detail", "")// 建议模糊模式下不要取这个值
            }
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    private fun tryGetLastKnownLocation(context: Context, onResult: (JSONObject?) -> Unit) {
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            complete(null, onResult)
            return
        }

        val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        val isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
        if (isNetworkEnabled){
            //网络定位
            val location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
            if (location == null) {
                HHLog.e(">>>>>>getLastKnownLocation>>>error")
                complete(null, onResult)
                return
            }
            HHLog.e(">>>>>>getLastKnownLocation>>>location result, latitude：" + location.latitude + "，longitude："+ location.longitude)
            coroutineScope.launch {
                val info = safeGetLocationInfo(context, location)
                complete(info, onResult)
            }
        } else {
            HHLog.e(">>>>>>isNetworkEnabled>>>false")
            complete(null, onResult)
        }
    }
}